// 实现这个项目的构建任务
const { src, dest, parallel, series, watch} = require('gulp')
const del = require('del')
const loadPlugins = require('gulp-load-plugins')
const eslint = require('gulp-eslint');
//browser-sync 并不是gulp的插件,需要单独引入
const bs = require('browser-sync')
const { stream } = require('browser-sync')
//自动的去加载全部插件
const plugins = loadPlugins()

//导入数据
const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'Features',
      link: 'features.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}
//clean
//del返回的是一个promise,
//那就意味着在del的完成过后,它可以标记clean任务执行完成，
const clean = ()=>{
  return del(['dist','temp'])//temp 用于存放临时文件
}

//样式编译
const style = () => {//私有任务，通过module.exports导出
  //通过src指定一个选项参数base设置转换的基准路径， 将基准路径后的目录结构保留下来
  //sass模块工作时，会认为下划线开头文件都是主文件当中依赖的一些文件，会被忽略掉，不会被转换。
  return src('src/assets/styles/*.scss',{base:'src'})
    .pipe(plugins.sass({outputStyle:'expanded'}))//outputStyle用于指定css 择器结束的这个括弧位置
    .pipe(dest('temp'))
    //.pipe(bs.reload(stream:true))
}

//脚本编译
const script = ()=>{
  return src('src/assets/scripts/*.js',{base:'src'})
  //babel默认只是一个ECMA script的一个转换平台。
  //平台实际上是不做任何事情的，他只是提供一个环境去做转换。
  //具体做事的是babel里面的一些插件，而presets就是一些插件的集合。
  //presents配置，它是一个数组，传入@babel/preset-env，它实际上是最新特性的一个整体的打包。

    .pipe(plugins.babel({presets:['@babel/preset-env']}))
    .pipe(dest('temp'))
}

//页面模板编译
const page = ()=>{
  //匹配所有子目录下的html文件：src('src/**/*.html',{base:'src'})
  return src('src/*.html',{base:'src'})
    .pipe(plugins.swig({data,defaults: { cache: false }}))//通过swig的data参数指定模板数据
    .pipe(dest('temp'))
}

//图片转换
const image = ()=>{
  return src('src/assets/images/**',{base:'src'})
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

//字体转换
const font = ()=>{
  return src('src/assets/fonts/**',{base:'src'})
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

//复制public目录
const extra = ()=>{
  return src('public/**',{base:'public'})
    .pipe(dest('dist'))
}
const lint = ()=>{
  return src('src/assets/scripts/*.js',{base:'src'})
    .pipe(eslint())
    .pipe(eslint.format())
}
const serve = ()=>{
  //watch指定两个参数
  //第一个参数呢就是globs，也就是要监视的文件
  //第二个参数是fn,也就是文件变化后我们要执行的任务函数
  watch('src/assets/styles/*.scss',style)
  watch('src/assets/scripts/*.js',script)
  watch('src/*.html',page)
  // watch('src/assets/images/**',image)
  // watch('src/assets/fonts/**',font)
  // watch('public/**',extra)
  //对图片字体等文件进行监听，变化时自动更新到浏览器
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'
  ],bs.reload)
  //初始化服务器相关配置
  bs.init({
    notify:false,//关闭右上角提示
    port:2000,//端口号，默认是3000
    //files 这个参数可以指定一个字符串，用来指定browser-sync启动过后需要监听的文件
    //这些文件发生改变后，browser-sync自动去更新浏览器。
    files:'dist/**',
    server:{
      baseDir:['temp','src','public'],//指定网站的根目录
      //通过routes指定特殊路由
      //请求发生后，会先看在routes里面有没有对应的配置。
      //如果有的话，会查找对应配置下的文件，否则的话就会找baseDir下面对应的文件。
      routes:{
        '/node_modules':'node_modules'
      }
    }
  })
}
const useref = ()=>{
  return src('temp/*.html',{base:'dist'})
    .pipe(plugins.useref({searchPath:['dist','.']}))
    .pipe(plugins.if(/\.js$/,plugins.uglify()))
    .pipe(plugins.if(/\.css$/,plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/,plugins.htmlmin({
      collapseWhitespace:true,
      minifyCSS:true,
      minifyJS:true
    })))
    .pipe(dest('dist'))
}
//组合任务
const compile = parallel(style,script,page)//去掉image,font等任务，减少不必要的编译开销

const build = series(clean,parallel(series(compile,useref),image,font,extra))//先删除这个dist目录下的文件，然后再去生成。

const develop = series(compile,serve)
module.exports = {
  clean,
  lint,
  serve,
  build,
  develop,
}
